# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = "restructuredtext en"
__all__ = []

from .. import hint
from .. import pilelib as stack
from ..forms import (freecell as FreeCellLayout, gypsy as GypsyLayout,)
from ..gamelib import info as gi, game, state
from ..packlib import place, info as cs
from ..piles import freecell as FreeCellStack
from ..utillib.misc import kwdefault

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class BakersGame(game.Game):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.freecell.FreecellLayout
        - row [8 horz S reserve and foundation, vert offset]
        - talon [1 SE, no offset]
        - foundation [4 horz NE, no offset]
        - reserve [4 horz NW, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play top. Base ace.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SuperMoveSS_RowStack
        Init all open, min 6 card. Build down in rank by same suit. Play top
        or sequence if possible as seperate plays.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x186cd, name='Bakerʼs Game', game_type=(GT.FREECELL |
                    GT.OPEN | GT.GNOME), decks=1, skill_level=SL.SKILL,
                    version='3.00')
    __author__ = 'Markus Oberhumer'
    __credits__ = ['C.L. Baker']
    __version__ = 7.70

    _layout_ = FreeCellLayout.FreeCellLayout
    _talon_ = stack.InitialDealTalon
    _foundation_ = stack.SS_Foundation
    _row_ = stack.SuperMoveSS_RowStack
    _reserve_ = stack.ReserveStack
    _hint_ = hint.CautiousDefaultHint

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=8, reserves=4, texts=False) -> Layout
        """
        kwdefault(kw, rows=8, reserves=4, texts=False)
        return super(BakersGame, self)._create_game(**kw)

    def _start(self, rows=7, **kw):
        """
        Deal initial cards for new game.
          - s[rows]: ~ *rows* open.

        .. \_start([rows=7]) -> None
        """
        for i in range(rows - 2):
            self.s['talon'].dealRow(frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].dealRowAvail()


class KingOnlyBakersGame(BakersGame):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.freecell.FreecellLayout
        - row [8 horz S reserve and foundation, vert offset]
        - talon [1 SE, no offset]
        - foundation [4 horz NE, no offset]
        - reserve [4 horz NW, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play top. Base ace.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SuperMoveSS_RowStack (base_rank=KING)
        Init all open, min 6 card. Build down in rank by same suit. Play top
        or sequence if possible as seperate plays. Base king.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x186ba, name='King Only Bakerʼs Game',
                    game_type=(GT.FREECELL | GT.OPEN), decks=1,
                    skill_level=SL.SKILL, version='2.90')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _row_ = Wrap(stack.SuperMoveSS_RowStack, base_rank=cs.KING)


class EightOff(KingOnlyBakersGame):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SW, no offset]
        - foundation [4 vert E, no offset]
        - reserve [8 horz S, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play top. Base ace.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SuperMoveSS_RowStack (base_rank=KING)
        Init 6 open card per. Build down in rank by same suit. Play top or
        sequence if possible as seperate plays. Base king.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Init every other 1 card. Build any top. Play top. Max 1
         card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x187a2, name='Eight Off', game_type=(GT.FREECELL |
                    GT.OPEN | GT.GNOME), decks=1, skill_level=SL.MOSTLY_SKILL,
                    version='2.01')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = GypsyLayout.GypsyLayout

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(reserves=8) -> Layout
        """
        kw.setdefault('reserves', 8)
        return super(EightOff, self)._create_game(**kw)

    def _start(self, rows=6, **kw):
        """
        Deal initial cards for new game.
          - s[rows]: *rows* ea open.
          - s[reserves][::2]: 1 ea open.

        .. \_start([rows=6]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].dealRow(rows=self.s['reserves'][::2])


class SeahavenTowers(KingOnlyBakersGame):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.freecell.TowersLayout
        - row [10 horz N, vert offset]
        - talon [1 SW, no offset]
        - foundation [2 horz NE, 2 horz NW, no offset]
        - reserve [4 horz N, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play top. Base ace.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SuperMoveSS_RowStack (base_rank=KING)
        Init 5 open card per. Build down in rank by same suit. Play top or
        sequence if possible as seperate plays. Base king.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Init 1 card on center 2. Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x186a9, name='Seahaven Towers', game_type=(GT.FREECELL
                    | GT.OPEN | GT.POPULAR | GT.GNOME | GT.XPAT), decks=1,
                    skill_level=SL.SKILL, altnames=('Sea Towers', 'Towers',
                    'Tours du Alice'), version='1.02')
    __author__ = 'Markus Oberhumer'
    __credits__ = ['Art Cabral']
    __version__ = 7.70

    _layout_ = FreeCellLayout.TowersLayout

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=10, bases=[1, 2, 3, 0]) -> Layout
        """
        kwdefault(kw, rows=10, bases=[1, 2, 3, 0])
        return super(SeahavenTowers, self)._create_game(**kw)

    def _start(self, rows=5, **kw):
        """
        Deal initial cards for new game.
          - s[rows]: *rows* ea open.
          - s[reserves][1:3]: 1 ea open.

        .. \_start([rows=5]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].dealRow(rows=(self.s['reserves'][1:3]))


class RelaxedSeahavenTowers(SeahavenTowers):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.freecell.TowersLayout
        - row [10 horz N, vert offset]
        - talon [1 SW, no offset]
        - foundation [2 horz NE, 2 horz NW, no offset]
        - reserve [4 horz N, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play top. Base ace.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SS_RowStack (base_rank=KING)
        Init 5 open card per. Build down in rank by same suit. Play sequence.
        Base king.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Init 1 card on center 2. Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x186a6, name='Relaxed Seahaven Towers',
                    game_type=(GT.FREECELL | GT.RELAXED | GT.OPEN), decks=1,
                    skill_level=SL.SKILL, version='1.01')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _row_ = Wrap(stack.SS_RowStack, base_rank=cs.KING)


class Tuxedo(game.Game):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SW, no offset]
        - foundation [4 vert E, no offset]
        - reserve [7 horz S, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (max_move=0)
        Build up in rank by same suit. Play top. Base 1st card.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SS_RowStack (mod=13)
        Init 7 open card per. Build down in rank by same suit wrap. Play
        sequence.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Init 1 card outer 1 and center. Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x18915, name='Tuxedo', game_type=(GT.FREECELL |
                   GT.OPEN), decks=1, skill_level=SL.MOSTLY_SKILL,
                   version='0.80fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = GypsyLayout.GypsyLayout
    _talon_ = stack.InitialDealTalon
    _foundation_ = Wrap(stack.Vary_SS_Foundation, max_move=0)
    _row_ = Wrap(stack.SS_RowStack, mod=13)
    _reserve_ = stack.ReserveStack
    _hint_ = hint.CautiousDefaultHint

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=7, reserves=7, playcards=16) -> Layout
        """
        kwdefault(kw, rows=7, reserves=7, playcards=16)
        return super(Tuxedo, self)._create_game(**kw)

    def _start(self, rows=7, **kw):
        """
        Deal initial cards for new game.
          - s[rows]: *rows* ea open.
          - s[reserves][::3]: 1 ea open.

        .. \_start([rows=7]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].dealRow(rows=self.s['reserve'][::3])


class Penguin(Tuxedo):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SW, no offset]
        - foundation [4 vert E, no offset]
        - reserve [7 horz S, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (max_move=0)
        Init base per 3. Build up in rank by same suit. Play top. Base 1st
        card.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SS_RowStack (mod=13)
        Init 7 open card per. Build down in rank by same suit wrap. Play
        sequence. Base -1 rank wrap of foundation.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x186e0, name='Penguin', game_type=(GT.FREECELL |
                    GT.OPEN), decks=1, skill_level=SL.MOSTLY_SKILL,
                    altnames=('Beak and Flipper',), version='3.00')
    __author__ = 'Markus Oberhumer'
    __credits__ = ['David Parlett']
    __version__ = 7.70

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return any single rank on top by suit, deck for _foundation_
        and _row_ deal.
        """
        return place.MoveToTop(cards, place.AnyOneRank)

    def _start(self, rows=7, **kw):
        """
        Deal initial cards for new game.
          - s[foundations]: 3. Set base rank.
          - s[rows]: *rows* open. Set base rank.

        .. \_start([rows=7]) -> None
        """
        base_rank = self.s['talon'].TOPCARD['rank']
        self['talon'].dealBaseCards(ncards=3, saveinfo=False)
        self._save_stack_caps(self.s['foundations'], base_rank=base_rank)
        self._save_stack_caps(self.s['rows'], base_rank=(base_rank - 1) % 13)
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()


class Opus(Penguin):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SW, no offset]
        - foundation [4 vert E, no offset]
        - reserve [5 horz S, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (max_move=0)
        Init base per 3. Build up in rank by same suit. Play top. Base 1st
        card.

      _row_ : pysollib.stack.Stack
        .. pysollib.stack.SS_RowStack (mod=13)
        Init 7 open card per. Build down in rank by same suit wrap. Play
        sequence. Base -1 rank wrap of foundation.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.CautiousDefaultHint
    """
    __info__ = dict(id=0x1884b, name='Opus', game_type=(GT.FREECELL |
                    GT.OPEN), decks=1, skill_level=SL.MOSTLY_SKILL,
                    version='0.91fc')
    __author__ = 'Skomoroh'
    __credits__ = ['Thomas Warfield']
    __version__ = 7.70

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(reserves=5) -> Layout
        """
        kw.setdefault('reserves', 5)
        return super(Opus, self)._create_game(**kw)


class Flipper(Tuxedo):
    """
    Finish 1 deck on foundation.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SW, no offset]
        - foundation [4 vert E, no offset]
        - reserve [7 horz S, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.InitialDealTalon
        No redeal.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation
        Build up in rank by same suit. Play none. Base 1st card.

      _row_ : pysollib.stack.Stack
        .. pysollib.stacks.frecell.Flipper_Row
        Init 7 open card per. Build down in rank by alt color. Play sequence.
        Flip top open when neighbor reserve has gap and close when has cards.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stack.ReserveStack
         Init 1 card outer 1 and center. Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.DefaultHint
    """
    __info__ = dict(id=0x18969, name='Flipper', game_type=(GT.FREECELL |
                    GT.ORIGINAL), decks=1, version='1.10fc',
                    skill_level=SL.MOSTLY_SKILL)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _row_ = FreeCellStack.Flipper_Row
    _foundation_ = stack.SS_Foundation
    _hint_ = hint.DefaultHint

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        After any play from row to reserve flip its neighbor row. After any
        play from reserve to row flip reserve neighbor row.

        *Parameters*:
          stack : pysollib.stack.Stack
            Pile just played.
        """
        for row, reserve in zip(self.s['rows'], self.s['reserves']):
            if row.cards:
                if ((reserve.cards and row.TOPCARD.face_up) or
                    (not reserve.cards and not row.TOP.face_up)):
                    self.flip(row)


PROVIDES = [BakersGame, KingOnlyBakersGame, EightOff, SeahavenTowers,
            RelaxedSeahavenTowers, Penguin, Opus, Tuxedo, Flipper]